from insts.inst import Index8Instruction, NoOperandInstruction


class Load(Index8Instruction):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind=''

    def execute(self, frame):
        if self.kind == 'int':
            val=frame.getLocalVars().getInt(self.index)
            frame.getOperandStack().pushInt(val)
        elif self.kind == 'float':
            val=frame.getLocalVars().getFloat(self.index)
            frame.getOperandStack().pushFloat(val)
        elif self.kind == 'ref':
            val=frame.getLocalVars().getRef(self.index)
            frame.getOperandStack().pushRef(val)
        elif self.kind == 'long':
            val=frame.getLocalVars().getLong(self.index)
            frame.getOperandStack().pushLong(val)
        elif self.kind == 'double':
            val=frame.getLocalVars().getDouble(self.index)
            frame.getOperandStack().pushDouble(val)

        else:
            raise ValueError("Invalid kind of variable to load")

class LoadConstant(NoOperandInstruction):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind=''
        self.index=0

    def execute(self, frame):
        if self.kind == 'int':
            val=frame.getConstantPool().getInt(self.index)
            frame.getOperandStack().pushInt(val)
        elif self.kind == 'float':
            val=frame.getConstantPool().getFloat(self.index)
            frame.getOperandStack().pushFloat(val)
        elif self.kind == 'long':
            val=frame.getConstantPool().getLong(self.index)
            frame.getOperandStack().pushLong(val)
        elif self.kind == 'double':
            val=frame.getConstantPool().getDouble(self.index)
            frame.getOperandStack().pushDouble(val)
        elif self.kind == 'ref':
            val=frame.getConstantPool().getRef(self.index)
            frame.getOperandStack().pushRef(val)
        else:
            raise ValueError("Invalid kind of constant to load")




class ILOAD(Load):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='int'

class FLOAD(Load):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='float'

class ALOAD(Load):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='ref'

class LLOAD(Load):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='long'


class DLOAD(Load):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='double'

class ALOAD_0(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='ref'
        self.index=0

class ALOAD_1(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='ref'
        self.index=1

class ALOAD_2(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='ref'
        self.index=2

class ALOAD_3(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='ref'
        self.index=3

class ILOAD_0(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='int'
        self.index=0

class ILOAD_1(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='int'
        self.index=1

class ILOAD_2(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='int'
        self.index=2

class ILOAD_3(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='int'
        self.index=3

class FLOAD_0(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='float'
        self.index=0

class FLOAD_1(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='float'
        self.index=1

class FLOAD_2(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='float'
        self.index=2

class FLOAD_3(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='float'
        self.index=3

class LLOAD_0(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='long'
        self.index=0

class LLOAD_1(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='long'
        self.index=1

class LLOAD_2(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='long'
        self.index=2

class LLOAD_3(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='long'
        self.index=3

class DLOAD_0(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='double'
        self.index=0

class DLOAD_1(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='double'
        self.index=1

class DLOAD_2(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='double'
        self.index=2

class DLOAD_3(LoadConstant):
    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind='double'
        self.index=3